# coding=utf-8
from queue import Queue
from threading import Thread
from datetime import datetime
from contextlib import contextmanager

import falcon
import pyipmi
from playhouse.shortcuts import model_to_dict
from pyipmi import interfaces

from db import models


class IPMIServerResource:
    def on_get(self, req: falcon.Request, resp: falcon.Response, resource_id: int = 0):
        if resource_id == 0:
            page = req.get_param_as_int("page", default=1)
            page_size = req.get_param_as_int("page_size", default=10)
            total = models.IPMIServer.select().count()
            resources = models.IPMIServer.select().order_by(-models.IPMIServer.created_time).paginate(page, page_size)

            data = {}
            q_task = Queue()
            for i in resources:
                item = model_to_dict(i)
                item.update({"ipmi_server_status": False, "power_status": False})
                data[i.ipaddress] = item
                q_task.put((i.ipaddress, i.user, i.password))

            # 利用多线程，加速获取 ipmi 状态
            q_result = Queue()
            for i in range(10):
                Thread(target=get_power_status, args=(q_task, q_result)).start()
            q_task.join()

            while True:
                if q_result.empty():
                    break
                ipaddress, ipmi_server_status, power_status = q_result.get()
                data[ipaddress].update({"ipmi_server_status": ipmi_server_status, "power_status": power_status})

            resp.media = {
                "total": total,
                "page": page,
                "page_size": page_size,
                "data": list(data.values())
            }
        else:
            resource = models.IPMIServer.get_by_id(resource_id)
            resp.media = model_to_dict(resource)

    def on_post(self, req: falcon.Request, resp: falcon.Response):
        media = req.get_media()
        new_server = models.IPMIServer()
        new_server.ipaddress = media.get("ipaddress")
        new_server.user = media.get("user")
        new_server.password = media.get("password")
        new_server.location = media.get("location")
        new_server.owner = media.get("owner")
        new_server.desc = media.get("desc", "")
        new_server.save()

    def on_delete(self, req: falcon.Request, resp: falcon.Response, resource_id: int):
        models.IPMIServer.delete_by_id(resource_id)

    def on_patch(self, req: falcon.Request, resp: falcon.Response, resource_id: int):
        media = req.get_media()
        try:
            resource = models.IPMIServer.get_by_id(resource_id)
        except models.IPMIServer.DoesNotExist:
            raise falcon.HTTPBadRequest(title=f"resource not exist: {resource_id}")

        resource.user = media.get("user")
        resource.password = media.get("password")
        resource.location = media.get("location")
        resource.owner = media.get("owner")
        resource.desc = media.get("desc", "")
        resource.updated_time = datetime.now()
        resource.save()

    def on_get_refresh(self, req: falcon.Request, resp: falcon.Response, resource_id: int):
        ipmi_server = models.IPMIServer.get_by_id(resource_id)
        data = {
            "ipaddress": ipmi_server.ipaddress,
            "ipmi_server_status": False,
            "power_status": False
        }

        try:
            with get_ipmi(ipmi_server.ipaddress, ipmi_server.user, ipmi_server.password) as ipmi_client:
                power_status = ipmi_client.get_chassis_status().power_on
                data["ipmi_server_status"] = True
                data["power_status"] = power_status
        except Exception:
            pass

        resp.media = data

    def on_get_shutdown(self, req: falcon.Request, resp: falcon.Response, resource_id: int):
        ipmi_server = models.IPMIServer.get_by_id(resource_id)
        print(f"关机：{ipmi_server.ipaddress}")
        with get_ipmi(ipmi_server.ipaddress, ipmi_server.user, ipmi_server.password) as ipmi_client:
            # ipmi_client.chassis_control_power_down()
            ipmi_client.chassis_control_soft_shutdown()

    def on_get_start(self, req: falcon.Request, resp: falcon.Response, resource_id: int):
        ipmi_server = models.IPMIServer.get_by_id(resource_id)
        print(f"开机：{ipmi_server.ipaddress}")
        with get_ipmi(ipmi_server.ipaddress, ipmi_server.user, ipmi_server.password) as ipmi_client:
            ipmi_client.chassis_control_power_up()


@contextmanager
def get_ipmi(ip: str, user: str, password: str, interface_type='lanplus') -> pyipmi.Ipmi:
    interface = interfaces.create_interface(interface='ipmitool', interface_type=interface_type)
    ipmi = pyipmi.create_connection(interface)
    ipmi.session.set_session_type_rmcp(ip, port=623)
    ipmi.session.set_auth_type_user(user, password)
    ipmi.session.establish()

    try:
        yield ipmi
    finally:
        ipmi.session.close()


def get_power_status(q_task: Queue, q_result: Queue):
    while True:
        if q_task.empty():
            return

        task = q_task.get()

        try:
            with get_ipmi(*task) as ipmi_client:
                power_status = ipmi_client.get_chassis_status().power_on
                q_result.put((task[0], True, power_status))
        except Exception:
            q_result.put((task[0], False, False))
        finally:
            q_task.task_done()
